home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / misc / fpl-v13.lha / fpl / src / sprintf.c < prev    next >
C/C++ Source or Header  |  1995-07-07  |  14KB  |  542 lines

  1. /******************************************************************************
  2.  *                   FREXX PROGRAMMING LANGUAGE                  *
  3.  ******************************************************************************
  4.  
  5.  sprintf.c
  6.  
  7.  Sprintf() function source code.
  8.  
  9.  *****************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #ifdef AMIGA
  41. #include <exec/types.h>
  42. #include <dos.h>
  43.  
  44. #elif defined(UNIX)
  45. #include <sys/types.h>
  46. #include <stdio.h>
  47. #endif
  48.  
  49. #include "script.h"
  50. #include "debug.h"
  51.  
  52. /* Lower-case digits.  */
  53. const uchar lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  54.  
  55. /* Upper-case digits.  */
  56. const uchar upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  57.  
  58. #define    OUTCHAR(x) do { CALL(AddCharBuffer(scr, string, (x))); done++; } while(0)
  59.  
  60. #define BUFFSIZE 40 /* 40 bytes buffer for ltostr() calcs */
  61.  
  62. #define ADD_STRING_LIMIT 10 /* strings longer than this get appended right
  63.                                away instead of added char by char */
  64.  
  65. ReturnCode REGARGS
  66. AddCharBuffer(struct Data *scr,
  67.           struct fplStr **string,
  68.           long add)
  69. {
  70.   ReturnCode ret;
  71.   switch(add) {
  72.     default:
  73.       if(scr->addchar_len<ADDBUFFER_SIZE) {
  74.                scr->addchar_buffer[scr->addchar_len++] = add;
  75.                break;
  76.       }
  77.     case ADD_FLUSH:
  78.       if(scr->addchar_len) {
  79.         CALL(AppendStringToString(scr, string,
  80.                                   scr->addchar_buffer,
  81.                                   scr->addchar_len));
  82.       }
  83.     case ADD_RESET:
  84.       scr->addchar_buffer[0]=(add>=0?add:'\0');
  85.       scr->addchar_len=(add>=0?1:0);
  86.       break;
  87.   }
  88.   return FPL_OK;
  89. }
  90.  
  91. ReturnCode REGARGS
  92. Sprintf(struct Data *scr,
  93.     struct fplStr **string,
  94.     uchar *format,
  95.     void **param_array,
  96.     uchar *param_types,
  97.     long argc)
  98. {
  99.   /* Base-36 digits for numbers.  */
  100.   const uchar *digits = lower_digits;
  101.  
  102.   /* Pointer into the format string.  */
  103.   register uchar *f;
  104.  
  105.   /* Number of characters written.  */
  106.   register size_t done = 0;
  107.  
  108.   long param_num=1; /* start with the first parameter */
  109.   ReturnCode ret;
  110.  
  111.   long param; /* current parameter to read */
  112.  
  113.   void *value; /* general purpose value holder */
  114.  
  115.   CALL(AddCharBuffer(scr, string, ADD_RESET));
  116.  
  117.   f = format;
  118.   while (*f != '\0') {
  119.       /* Type modifiers.  */
  120.       uchar is_short, is_long, is_long_double;
  121.  
  122.       /* Format spec modifiers.  */
  123.       uchar space, showsign, left, alt;
  124.  
  125.       /* Padding character: ' ' or '0'.  */
  126.       uchar pad;
  127.       /* Width of a field.  */
  128.       register long width;
  129.       /* Precision of a field.  */
  130.       long prec;
  131.  
  132.       /* Decimal integer is negative.  */
  133.       uchar is_neg;
  134.  
  135.       /* Current character of the format.  */
  136.       uchar fc;
  137.  
  138.       /* Base of a number to be written.  */
  139.       long base;
  140.       /* Integral values to be written.  */
  141.       unsigned long num;
  142.       long signed_num;
  143.  
  144.       if (*f != '%') {
  145.       /* This isn't a format spec, so write
  146.          everything out until the next one.  */
  147.       uchar *next = strchr(f + 1, '%');
  148.       if (next == NULL)
  149.         next = strchr(f + 1, '\0');
  150.       if (next - f > ADD_STRING_LIMIT) {
  151.           /*
  152.            * bonka pa hela klabbet pa en gang!
  153.            */
  154.               CALL(AddCharBuffer(scr, string, ADD_FLUSH));
  155.           CALL(AppendStringToString(scr, string, f, next - f));
  156.           done += next - f;
  157.           f = next;
  158.       }
  159.       else
  160.         while (f < next)
  161.           OUTCHAR(*f++);
  162.       continue;
  163.       }
  164.  
  165.       ++f;
  166.  
  167.       /* Check for "%%".  Note that although the ANSI standard lists
  168.      '%' as a conversion specifier, it says "The complete format
  169.      specification shall be `%%'," so we can avoid all the width
  170.      and precision processing.  */
  171.       if (*f == '%') {
  172.       ++f;
  173.       OUTCHAR('%');
  174.       continue;
  175.       }
  176.  
  177.       /* Check for spec modifiers.  */
  178.       space = showsign = left = alt = 0;
  179.       pad = ' ';
  180.       while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0') {
  181.     switch (*f++) {
  182.       case ' ':
  183.         /* Output a space in place of a sign, when there is no sign.  */
  184.         space = 1;
  185.         break;
  186.       case '+':
  187.         /* Always output + or - for numbers.  */
  188.         showsign = 1;
  189.         break;
  190.       case '-':
  191.         /* Left-justify things.  */
  192.         left = 1;
  193.         break;
  194.       case '#':
  195.         /* Use the "alternate form":
  196.            Hex has 0x or 0X, FP always has a decimal point.  */
  197.         alt = 1;
  198.         break;
  199.       case '0':
  200.         /* Pad with 0s.  */
  201.         pad = '0';
  202.         break;
  203.     }
  204.       }
  205.       if (left)
  206.     pad = ' ';
  207.  
  208.       /* Get the field width.  */
  209.       width = 0;
  210.       param = 0;
  211.       if (*f == '*') {
  212.       /* The field width is given in an argument.
  213.          A negative field width indicates left justification.  */
  214.         if(isdigit(f[1]) && '$' == f[2]) {
  215.           width = f[1] - '0';
  216.           if(width<1)
  217.             width=1;
  218.       if(width<argc)
  219.           width = (long) param_array[ width ];
  220.       else
  221.           /* BEEEEEEEEEP Tried to read unset parameter, use 1 ! */
  222.           width = 1;
  223.         }
  224.         else {
  225.       if(param_num<argc)
  226.           width = (long) param_array[param_num++];
  227.       else
  228.           /* BEEEEEEEEEP Tried to read unset parameter, use 1 ! */
  229.           width = 1;
  230.     }
  231.         if (width < 0) {
  232.           width = - width;
  233.           left = 1;
  234.         }
  235.         ++f;
  236.       }
  237.       else {
  238.         if(isdigit(f[1]) && '$' == f[2]) {
  239.           param = f[1]-'0';
  240.           if(param<1)
  241.             param=1; /* use no less than 1! */
  242.         }
  243.     while (isdigit(*f)) {
  244.           width *= 10;
  245.           width += *f++ - '0';
  246.     }
  247.       }
  248.  
  249.       /* Get the precision.  */
  250.       /* -1 means none given; 0 means explicit 0.  */
  251.       prec = -1;
  252.       if (*f == '.') {
  253.       ++f;
  254.       if (*f == '*') {
  255.             if(isdigit(f[1]) && '$' == f[2]) {
  256.               prec = f[1] - '0';
  257.               if(prec<1)
  258.                 prec=1;
  259.           if(prec<argc)
  260.           prec = (long) param_array[ prec ];
  261.           else
  262.           /* BEEEEEEEEEP Tried to read unset parameter, use -1 ! */
  263.           prec = -1;
  264.             }
  265.             else {
  266.               /* The precision is given in an argument.  */
  267.           if(param_num<argc)
  268.           prec = (long) param_array[param_num++];
  269.           else
  270.           /* BEEEEEEEEEP Tried to read unset parameter, use 1 ! */
  271.           prec = -1;
  272.         }
  273.             /* Avoid idiocy.  */
  274.             if (prec < 0)
  275.               prec = -1;
  276.             ++f;
  277.           }
  278.       else if (isdigit(*f)) {
  279.           prec = 0;
  280.           while (*f != '\0' && isdigit(*f))
  281.         {
  282.           prec *= 10;
  283.           prec += *f++ - '0';
  284.         }
  285.         }
  286.       }
  287.  
  288.       /* Check for type modifiers.  */
  289.       is_short = is_long = is_long_double = 0;
  290.       while (*f == 'h' || *f == 'l' || *f == 'L') {
  291.     switch (*f++) {
  292.         case 'h':
  293.           /* int's are short int's.  */
  294. #if 0
  295.           /* ignored in FPL since there are no true shorts! */
  296.           is_short = 1;
  297. #endif
  298.           break;
  299.         case 'l':
  300.           /* int's are long int's.  */
  301.           is_long = 1;
  302.           break;
  303.         case 'L':
  304.           /* double's are long double's, and int's are long long int's.  */
  305.           is_long_double = 1;
  306.           break;
  307.         }
  308.       }
  309.       /* Format specification.  */
  310.       fc = *f++;
  311.  
  312.       if((param && param<argc) || (!param && param_num<argc))
  313.       value = (void *)(param?param_array[param]:param_array[param_num++]);
  314.       else
  315.       value = (void *)-1; /* illegal use causes -1 ! */
  316.  
  317.       switch (fc) {
  318.       case 'i':
  319.       case 'd':
  320.         /* Decimal integer.  */
  321.         base = 10;
  322.             signed_num = (long) value;
  323.  
  324.         is_neg = signed_num < 0;
  325.         num = is_neg ? (- signed_num) : signed_num;
  326.         goto number;
  327.  
  328.       case 'u':
  329.         /* Decimal unsigned integer.  */
  330.         base = 10;
  331.         goto unsigned_number;
  332.  
  333.           case 'b':
  334.             /* Binary unsigned integer.  */
  335.             base = 2;
  336.             goto unsigned_number;
  337.  
  338.       case 'o':
  339.         /* Octal unsigned integer.  */
  340.         base = 8;
  341.         goto unsigned_number;
  342.  
  343.       case 'X':
  344.         /* Hexadecimal unsigned integer.  */
  345.       case 'x':
  346.         /* Hex with lower-case digits.  */
  347.  
  348.         digits = fc == 'X' ? upper_digits : lower_digits;
  349.  
  350.         base = 16;
  351.  
  352.       unsigned_number:;
  353.         /* Unsigned number of base BASE.  */
  354.             num = (unsigned long) value;
  355.  
  356.         is_neg = 0;
  357.  
  358.       number:;
  359.         /* Number of base BASE.  */
  360.         {
  361.           uchar work[BUFFSIZE];
  362.           uchar *workend = &work[sizeof(work) - 1];
  363.           register uchar *w;
  364.  
  365.           /* Supply a default precision if none was given.  */
  366.           if (prec == -1)
  367.         prec = 1;
  368.  
  369.           /* Put the number in WORK.  */
  370.           w = workend;
  371.           while (num > 0) {
  372.                 *w-- = digits[num % base];
  373.                 num /= base;
  374.               }
  375.           width -= workend - w;
  376.           prec -= workend - w;
  377.  
  378.           if (alt && base == 8 && prec <= 0) {
  379.                 *w-- = '0';
  380.                 --width;
  381.               }
  382.  
  383.           if (prec > 0) {
  384.                 width -= prec;
  385.                 while (prec-- > 0)
  386.                   *w-- = '0';
  387.               }
  388.  
  389.           if (alt && base == 16)
  390.         width -= 2;
  391.  
  392.           if (is_neg || showsign || space)
  393.         --width;
  394.  
  395.           if (!left && pad == ' ')
  396.         while (width-- > 0)
  397.           OUTCHAR(' ');
  398.  
  399.           if (is_neg)
  400.         OUTCHAR('-');
  401.           else if (showsign)
  402.         OUTCHAR('+');
  403.           else if (space)
  404.         OUTCHAR(' ');
  405.  
  406.           if (!left && pad == '0')
  407.         while (width-- > 0)
  408.           OUTCHAR('0');
  409.  
  410.           if (alt && base == 16) {
  411.           OUTCHAR('0');
  412.           OUTCHAR(fc);
  413.               }
  414.  
  415.           /* Write the number.  */
  416.           while (++w <= workend) {
  417.         OUTCHAR(*w);
  418.               }
  419.  
  420.           if (left)
  421.         while (width-- > 0)
  422.           OUTCHAR(' ');
  423.         }
  424.         break;
  425.  
  426.       case 'c':
  427.         /* Character.  */
  428.         num = (long) value;
  429.         if (!left)
  430.           while (--width > 0)
  431.         OUTCHAR(' ');
  432.         OUTCHAR((uchar) num);
  433.         if (left)
  434.           while (--width > 0)
  435.         OUTCHAR(' ');
  436.         break;
  437.  
  438.       case 's':
  439.         /* String.  */
  440.         {
  441.           static uchar null[] = "[ERR]";
  442.               uchar *str;
  443.           size_t len;
  444.  
  445.           str = (uchar *) value;
  446.           if ( str == NULL ||
  447.           (param && param>=argc) || (!param && param_num-1 >= argc) ||
  448.                   (param?param_types[param]:param_types[param_num-1]) !=
  449.                   FPL_STRARG )
  450.           /* Write "(err)" if there's space.  */
  451.           if (prec == -1 || prec >= (long) sizeof(null) - 1) {
  452.             str = null;
  453.             len = sizeof(null) - 1;
  454.           }
  455.           else {
  456.             str = "";
  457.             len = 0;
  458.           }
  459.           else
  460.           len = strlen(str);
  461.  
  462.           if (prec != -1 && (size_t) prec < len)
  463.         len = prec;
  464.           width -= len;
  465.  
  466.           if (!left)
  467.         while (width-- > 0)
  468.           OUTCHAR(' ');
  469.  
  470.           if (len < ADD_STRING_LIMIT)
  471.                   while (len-- > 0)
  472.                       OUTCHAR(*str++);
  473.           else {
  474.                   CALL(AddCharBuffer(scr, string, ADD_FLUSH));
  475.                   CALL(AppendStringToString(scr, string, str, len));
  476.                   done += len;
  477.               }
  478.           if (left)
  479.         while (width-- > 0)
  480.           OUTCHAR(' ');
  481.         }
  482.         break;
  483.  
  484.       case 'p':
  485.           case 'P': /* support this too, not ANSI though! */
  486.         /* Generic pointer.  */
  487.         {
  488.               void *ptr;
  489.           ptr = (void *) value;
  490.           if (ptr != NULL) {
  491.                 /* If the pointer is not NULL, write it as a %#x spec.  */
  492.                 base = 16;
  493.                 digits = fc == 'P' ? upper_digits : lower_digits;
  494.                 fc = fc == 'P'?'X':'x';
  495.                 alt = 1;
  496.                 num = (unsigned long) ptr;
  497.                 is_neg = 0;
  498.                 goto number;
  499.               }
  500.           else {
  501.                 /* Write "(nil)" for a nil pointer.  */
  502.                 static uchar nil[] = "(nil)";
  503.                 register uchar *p;
  504.  
  505.                 width -= sizeof(nil) - 1;
  506.                 if (left)
  507.                   while (width-- > 0)
  508.                     OUTCHAR(' ');
  509.                 for (p = nil; *p != '\0'; ++p)
  510.                   OUTCHAR(*p);
  511.                 if (!left)
  512.                   while (width-- > 0)
  513.                     OUTCHAR(' ');
  514.               }
  515.         }
  516.         break;
  517.  
  518.       case 'n':
  519.         /* Answer the count of characters written.  */
  520.             {
  521.               struct Identifier *ident;
  522.           if((param && param<argc) || (!param && param_num < argc)) {
  523.         if((param?param_types[param]:param_types[param_num]) ==
  524.            FPL_INTVARARG) {
  525.           ident = (struct Identifier *) value;
  526.           ident->data.variable.var.val32[0] = done;
  527.         }
  528.           }
  529.           /* else
  530.          ILLEGALY USED !!!!! */
  531.             }
  532.         break;
  533.     }
  534.  
  535.   }
  536.  
  537.   CALL(AddCharBuffer(scr, string, ADD_FLUSH)); /* flush temp buffer */
  538.  
  539.   return FPL_OK;
  540. }
  541.  
  542.